
#include <iostream>
#include <sstream>

#include "bocat/common/base64.hpp"
#include "bocat/common/time.hpp"
#include "bocat/common/logging.hpp"

#include "record.hpp"
#include "aubin.hpp"

namespace   fetcab   {

Aubin::Aubin( const char* ini_filename, const char* ini_section )
		:  _bin_index( ini_filename, ini_section )
{
}

Aubin::~Aubin()
{
}

///////////////////////////////////////////////////////////////////////
//


int 
Aubin::insert( const std::string& kpin,
         const std::string& key,
         const std::string& data )
{
	boost::mutex::scoped_lock   _scoped_lock( _mutex );

	std::string	skey = getSkeyByKpin( kpin );
	_bin_index.put( skey, data );

    return  0;
}


/*
int 
Aubin::insertAppend( const std::string& kpin,
         const std::string& key,
         const std::string& data )
{
	boost::mutex::scoped_lock   _scoped_lock( _mutex );

	std::string	skey = getSkeyByKpin( kpin );

	_bin_index.put( skey, data );

    return  0;
}


int 
Aubin::insertIgnore( const std::string& kpin,
         const std::string& key,
         const std::string& data )
{
	boost::mutex::scoped_lock   _scoped_lock( _mutex );

    // STEP. check if key exists
	std::string	skey = getSkeyByKpin( kpin );
	std::string	data_got;
	try {
		_bin_index.get( skey, data_got );
	}
	catch( std::exception& e ) {
		std::ostringstream	msg;
		msg << "fail to check existence for key '" << key << "' -- " << e.what();
		throw std::runtime_error( msg.str() );
	}

    // STEP. if key exists, ignore it
	if ( data_got.size() > 0 ) {
		return 0;
	}

	_bin_index.put( skey, data );

    return  0;
}
*/


int 
Aubin::find( const std::string& kpin,
         const std::string& key,
               std::string& data )
{   
	boost::mutex::scoped_lock   _scoped_lock( _mutex_read );

	std::string	skey = getSkeyByKpin( kpin );
	try {
		_bin_index.get( skey, data );
	}
	catch( std::exception& e ) {
		std::ostringstream	msg;
		msg << "fail to get data for key '" << key << "' -- " << e.what();
		throw std::runtime_error( msg.str() );
	}


    return  data.size();
}


int 
Aubin::erase( const std::string& kpin,
           const std::string& key )
{
	boost::mutex::scoped_lock   _scoped_lock( _mutex );

    // STEP. check if key exists
	std::string	skey = getSkeyByKpin( kpin );
	std::string	data_got;
	try {
		_bin_index.get( skey, data_got );
	}
	catch( std::exception& e ) {
		std::ostringstream	msg;
		msg << "fail to check existence for key '" << key << "' -- " << e.what();
		throw std::runtime_error( msg.str() );
	}

    // STEP. if key does NOT exist, just return
	if ( data_got.size() < 1 ) {
		return 0;
	}

    // STEP. erase the record
	//       . erase index from file cell
	_bin_index.erase( skey );

    return  0;
}


///////////////////////////////////////////////////////////////////////
//

/*
int
Aubin::insertAppend( const std::vector< std::string >& kpin_v,
					 const std::vector< std::string >& key_v,    
					 const std::vector< std::string >& data_v )
{
	boost::mutex::scoped_lock   _scoped_lock( _mutex );

	std::vector< Record >	record_v;

	// STEP. prepare
	for (size_t k=0; k<key_v.size(); ++k) {
		Record	r;
		r.kpin = kpin_v[ k ];
		r.key  = key_v[ k ];
		r.data = data_v[ k ];

		r.skey = getSkeyByKpin( r.kpin );

		record_v.push_back( r );
	}

    // STEP. check if key exists
	try {
		_bin_index.get( record_v );
	}
	catch( std::exception& e ) {
		std::ostringstream	msg;
		msg << "fail to check existence for keys -- " << e.what();
		throw std::runtime_error( msg.str() );
	}

    // STEP. insert the record
	//       . put data into file cell
	//       . put location into index
	for (size_t k=0; k<key_v.size(); ++k) {
		Record&	r = record_v[ k ];
		r.skey_b64 = bocat::common::base64_encode( r.skey );
		r.kpin_b64 = bocat::common::base64_encode( r.kpin );

		r.prev_loc = r.loc;
		r.loc.clear();
	}

	_filecell.append( record_v );
	_bin_index.put( record_v );

    return  0;
}
*/

///////////////////////////////////////////////////////////////////////
//


///////////////////////////////////////////////////////////////////////
//


const std::string   
Aubin::getSkeyByKpin( const std::string& kpin )
{
	char	skey[12];
	u_int32_t	skey_size;

	memset(skey, 0, sizeof(skey));
	skey_size = (kpin.size() > sizeof(skey)) ? sizeof(skey) : kpin.size();
	memcpy( skey, kpin.c_str() + (kpin.size() - skey_size), skey_size );

	return	std::string( skey, skey_size );
}


///////////////////////////////////////////////////////////////////////
//


}   //// namespace fetcab

